package com.aaamvc.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import javassist.NotFoundException;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;

import org.apache.commons.beanutils.BeanUtils;

public class ReflectUtil {

	/**
	 * 
	 * @param actionName
	 *            userAction_save.do
	 * @param map
	 *            保存配置文件的Action
	 * @param reqMap
	 *            请求参数map用于封装到实体类
	 * @return
	 */
	public static String getReturnPath(String requestUrl,
			List<String> packages, Map reqMap, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		String returnPath = invokeMethod(reqMap,requestUrl,packages,request,response);
		 //封装请求参数到Action属性
		return returnPath;
	}

	// 找到类和方法
	public static String invokeMethod(
			Map reqMap,
			String requestUrl,
			List<String> packages, 
			HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		Map<String, Method> request_method = new HashMap<String, Method>();
		String requestMapping = "";// 控制器的请求路径
		String returnPath = ""; // 执行方法返回地址

		// 1.查找类
		Class invokedCls = null;
		String invokedClsAnn = StringUtil.getRequestController(requestUrl);
		for (String pack : packages) {
			List<Class<?>> classes = ClassUtil.getClasses(pack);
			for (Class clas : classes) {
				// 获取该类的存在@Controller的方法
				if (clas.isAnnotationPresent(Controller.class)) {
					// 判读类是否存在@RequestMapping注解
					if (clas.isAnnotationPresent(RequestMapping.class)) {
						RequestMapping rmMapping = (RequestMapping) clas.getAnnotation(RequestMapping.class);
						requestMapping = rmMapping.value();
						if (requestMapping.startsWith("/")) {
							requestMapping = requestMapping.substring(1);
						}
						if (requestMapping.equals(invokedClsAnn)) {
							invokedCls = clas;//找到与请求地址匹配的Controller
							break;
						}
					}
				}
			}
		}
		Object object = invokedCls.newInstance();
		bindingProperty(reqMap, object);
		String invokedMethod = StringUtil.getRequestMethod(requestUrl);
		// 2.查找类的所有方法
		Method[] methods = invokedCls.getDeclaredMethods();
		for (Method method : methods) {
			if (method.isAnnotationPresent(RequestMapping.class)) {
				requestMapping = ((RequestMapping) method.getAnnotation(RequestMapping.class)).value();
				if (invokedMethod.equals(requestMapping)) {
					try {
						returnPath = (String) method.invoke(object,request, response);
						break;
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}

		return returnPath;
	}

	public static List bindingMethodParam(Class clazz, Map reqMap,
			String methodName, HttpServletRequest request,
			HttpServletResponse response) {
		List paramList = new ArrayList();
		try {
			ClassPool pool = ClassPool.getDefault();
			pool.insertClassPath(new ClassClassPath(clazz));
			CtClass sp = pool.get(clazz.getName());

			CtMethod cm = sp.getDeclaredMethod(methodName);

			// 使用javaassist的反射方法获取方法的参数名
			MethodInfo methodInfo = cm.getMethodInfo();
			CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
			LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute
					.getAttribute(LocalVariableAttribute.tag);
			String[] paramNames = new String[cm.getParameterTypes().length];
			int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
			for (int i = 0; i < paramNames.length; i++) {
				paramNames[i] = attr.variableName(i + pos);
				String typeName = cm.getParameterTypes()[i].getName();
				// 普通参数给参数赋值，
				if (reqMap.containsKey(paramNames[i])) {
					String values[] = (String[]) reqMap.get(paramNames[i]);
					if (typeName.equals("int")
							|| typeName.equals(Integer.class.getName())) {
						paramList.add(Integer.parseInt(values[0]));
					}
				}
				// 非普通参数，request,response 直接传给Action方法
				if (typeName.equals("javax.servlet.http.HttpServletRequest")) {
					paramList.add(request);
				}
				if (typeName.equals("javax.servlet.http.HttpServletResponse")) {
					paramList.add(response);
				}
				System.out.println("==参数类型="
						+ cm.getParameterTypes()[i].getName());
				// 如果是实体类，则遍历进行封装

			}

			// paramNames即参数名
			for (int i = 0; i < paramNames.length; i++) {
				System.out.println("==参数名称=" + paramNames[i]);
			}

		} catch (NotFoundException e) {
			e.printStackTrace();
		}
		return paramList;
	}

	/**
	 * 封装请求参数
	 * 
	 * @param reqMap
	 *            请求参数map
	 * @param object
	 *            Action对象
	 * @throws Exception
	 */
	public static void bindingProperty(Map reqMap, Object object)
			throws Exception {
		Field[] fields = object.getClass().getDeclaredFields();
		for (int i = 0; i < fields.length; i++) {
			Class fieldClass = fields[i].getType();
			Object fieldObject = null;
			Field[] properyField = fieldClass.getDeclaredFields();
			for (Field entityField : properyField) { // 实体类的属性
				if (reqMap.containsKey(entityField.getName())) {
					if (fieldObject == null) {
						fieldObject = fieldClass.newInstance();
						BeanUtils.populate(fieldObject, reqMap);
						fields[i].setAccessible(true);
						fields[i].set(object, fieldObject);
						break;
					}
				}
			}
		}
	}
}
